#include "ProcessScheduler.h"
#include "ResourceScheduler.h"
#include "NOW.h"
#include "sys/IO.h"
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include "sys/Memory.h"
#include "sys/buffer.h"
#include "sys/shm.h"
#include "sys/ipc.h"



static void Exit(int pid, int retVal,int t);
static void forkProcess(int fa_pid, int para, int T);
static void killProcess(int pid, int targetId, int T);
static void waitProcess(int waiter, int t);
static int setProcessPriority(int pid, int priority, int t);
static void loadAdd(int pid, unsigned int add, int T);
static void storeAdd(int pid, unsigned int add, int T);



//在一个时间片内模拟指令的执行，主要进行指令细化和分派给下面5个函数
//返回值表示时间片结束时指令是否终止，1是未终止
static int _processAct(int pid, int T){ 
    if(jobs[pid].state==TERMINATED){
        Exit(pid,EXIT_KILLED_BY_PARENTS,T);
        return 0;
    } 
    int i=RR_STIME;
    while(i>0){
        JobActNode* pc= jobs[pid].pc;

        if(pc==NULL){   //指令到达末尾
            Log(pid,"terminated for unknown error.",T,1);
            Exit(pid,EXIT_ENDLESS_ERROR,T);
            return 0;
        }

        if(i>pc->time){
            i-=pc->time;
        }else{
            pc->time-=i;
            return 1;
        }

        int t=T+RR_STIME-i;
        printf("pid %d op %s at time %d and procN=%d\n",pid,ins[pc->op],t,procN);
        switch(pc->op){
            case POP_APPL:applyResource(pid,pc->param,t); break;
            case POP_END:Exit(pid,EXIT_NORMALLY,t); break;
            case POP_FORK:forkProcess(pid,t,pc->param); break;
            case POP_KILL:killProcess(pid,pc->param,t); break;
            case POP_LOAD:loadAdd(pid, (unsigned)pc->param, T);break;
            case POP_STORE:storeAdd(pid, (unsigned)pc->param, T);break;
            case POP_RELS:releaseResources(pid, pc->param,t); break;
            case POP_SETP:setProcessPriority(pid,pc->param,t); break;
            case POP_WAITP:waitProcess(pid,t); break;
            default: break;
        }

        if(jobs[pid].state==WAITING||jobs[pid].state==TERMINATED)  return 0;

        
        jobs[pid].pc=pc->next;
    }

    return 0;
    
}

static void loadAdd(int pid, unsigned int add, int T){
    if(!Load(pid,add,T)){
        LogErr("Segmentation fault!",T);
        killProcess(jobs[pid].pa_id,pid,T);
    } 
}

static void storeAdd(int pid, unsigned int add, int T){
    if(!Store(pid,add,T)){
        LogErr("Segmentation fault!",T);
        killProcess(jobs[pid].pa_id,pid,T);
    }
}

//下面5个函数是指令的具体实现
//设置pid进程优先级，若成功返回1，若失败返回0
static int setProcessPriority(int pid, int priority, int t){
    jobs[pid].priority=priority;
}
//创建进程，记录进程进入内存的时间
static void createProcess(int pid, int arrive_time, int priority, int fa_pid){
    jobs[pid].id = pid;
    jobs[pid].pa_id = fa_pid;
    jobs[pid].ch_id = NULL;
    //jobs[pid].gid = pid;
    jobs[pid].arrive_time = arrive_time;
    jobs[pid].priority = priority;
    jobs[pid].state = READY;
    jobs[pid].start_time = -1;
    jobs[pid].marker=0;
    if(fa_pid!=-1) jobs[pid].pc=jobs[fa_pid].pc->next;
    else jobs[pid].pc=jobActs[pid];
}
//找到一个空余pid然后分配//复制父进程fa_pid创建子进程ch_pid
static int getpid(){
    for(int i=0;i<MAX_JOB_N;i++){
        if(vac[i]==0){
            vac[i]=1;
            return i;
        }
    }
}
//实现fork指令，用getpid获取子进程id
static void forkProcess(int fa_pid, int T,int param){
    int pid=getpid(); //系统自动分配pid
    procN++;

    ProcessLNode * J= jobs[fa_pid].ch_id;
    jobs[fa_pid].ch_id=(ProcessLNode*)malloc(sizeof(ProcessLNode));
    jobs[fa_pid].ch_id->next_id=J;
    jobs[fa_pid].ch_id->id=pid;

    
    
   
    
    /*
    jobActs[pid]=(JobActNode *)malloc(sizeof(JobActNode));
    jobActs[pid]->next=NULL;
    jobActs[pid]->op=POP_END;
    jobActs[pid]->time=param;
    */

    createProcess(pid, T, jobs[fa_pid].priority, fa_pid);
    if(!Mmap(pid,T)) LogErr("fail to Mmap!",T);

    if(!q_full(&Ready)) q_push(&Ready,pid,PSA);
    else LogErr("Ready queue is full!",T);
}
//程序pid发送信号终止程序targetId的执行，
static void killProcess(int pid, int targetId, int T){
    jobs[targetId].state=TERMINATED;
}
//让进程waiter等待target进程执行完毕
static void waitProcess(int waiter, int t){
    if(jobs[waiter].ch_id==NULL) return ;
    int ch=jobs[waiter].ch_id->id;
    jobs[ch].marker=1;
    if(jobs[ch].state==TERMINATED) {
        return ;
    }
    /*if(!q_full(&waitpid_q))    q_push(&waitpid_q,waiter,FCFS);
    else LogErr("waitingpid queue is full");*/

    jobs[waiter].state=WAITING;
}
//程序pid终止自身执行，唤醒等待的父进程（如果有），并释放所有占用资源
static void Exit(int pid, int retVal,int t){
    --procN; 
    jobs[pid].state = TERMINATED;
    jobs[pid].exit_val = retVal;
    jobs[pid].completion_time=t;
    jobs[pid].id=-1;
    while(jobs[pid].ch_id!=NULL){
        ProcessLNode * P=jobs[pid].ch_id->next_id;
        killProcess(pid, jobs[pid].ch_id->id,t);
        free(jobs[pid].ch_id);
        jobs[pid].ch_id=P;
    }

    
    int pa_id=jobs[pid].pa_id;
    int marker=jobs[pid].marker;    //marker标记是否有父进程等待它结束
    if(pa_id!=-1 && marker){
        jobs[pa_id].state=READY;
        q_popout(&waitpid_q,pa_id); //从队列指定剔除一个元素
        if(!q_full(&Ready)) q_push(&Ready,pa_id,PSA);
        else LogErr("Ready queue is full!",t);
    } 
    
    for(int r=0;r<MAX_RESOURCE_NUM;r++){
        for(int i=0;i<rsc_num[r];i++){
            if(sleep[r].occupy[i]==pid) {
                sleep[r].occupy[i]=-1;
                Remain[r]++;
            }
        }
    }
    if(!Munmap(pid,t)) LogErr("fail to Munmap!",t);
    
}











//操作系统启动时调用
void init_processes(){
    for (int i=0;i<MAX_JOB_N;++i){
        jobs[i].id = -1;
        jobs[i].marker=0;
        jobActs[i]=NULL;
        memset(jobs[i].resource_remain,0,sizeof(jobs[i].resource_remain));
        memset(jobs[i].resource_requests,0,sizeof(jobs[i].resource_requests));
    }
    procN = 0;
    memset(vac,0,sizeof(vac));
    //初始化全部队列
    q_init(&New, 0);
    q_init(&waitpid_q, 0);
    for(int i=0; i<MAX_RESOURCE_NUM; i++){
        q_init(&sleep[i],rsc_num[i]);
    }
    for(int i=0;i<MAX_RESOURCE_NUM;i++){
        Remain[i]=rsc_num[i];
    }
    

    for (int c=0;c<CORE_N;++c)
        Running[c]=-1;

    //创建信号量和共享内存区域：
    shmid_t shmid = shmget(BUFFER_NAME, sizeof(Buffer));
    if (shmid == NULL) {
        printf("shmget error\n");
        exit(1);
    }

    // 映射共享内存​
    buffer = (Buffer*)shmat(shmid);
    if (buffer == NULL) {
        printf("shmat error\n");
        shmctl(shmid);
        exit(1);
    }

    // 初始化缓冲区​
    buffer->count=0;
    buffer->in=0;
    buffer->out=0;
    buffer->End_or_Not=1;
    memset(buffer->strings,0,sizeof(buffer->strings));

    Semid = sem_init(SEM_NAME,1);
    if(Semid==NULL){
        printf("semaphore init failed\n");
        exit(1);
    }else{
        printf("semaphore create successfully\n");
    }


}
//释放链表//操作系统结束时调用
void free_processes(){
    for(int i=0;i<MAX_JOB_N;i++){   //释放代码区
        JobActNode* J=jobActs[i];
        while(J){
            JobActNode* T=J;
            J=J->next;
            free(T);
        }
    }
    for(int i=0;i<MAX_JOB_N;i++){   //释放子进程
        ProcessLNode* P=jobs[i].ch_id;
        while(P){
            ProcessLNode* T=P;
            P=P->next_id;
            free(T);
        }
    }
    q_free(&New);                   //释放资源
    q_free(&Ready);
    for(int i=0;i<MAX_RESOURCE_NUM;i++){
        q_free(&sleep[i]);
    }

    buffer->End_or_Not=0;

}


//下面6个函数对Ins初始指令队列进行预处理，
//包括：指令解析，指令分类，收集所需资源信息，排序，计算相对时间
int compare(const void *a, const void *b) {
    _Arrive *arrive_a = (_Arrive *)a;
    _Arrive *arrive_b = (_Arrive *)b;
    return arrive_a->time - arrive_b->time;
}
void swap(JobActNode* a, JobActNode* b) {

    int temp_time = a->time;
    ProcessOperation temp_op = a->op;
    int temp_param = a->param;


    a->time = b->time;
    a->op = b->op;
    a->param = b->param;


    b->time = temp_time;
    b->op = temp_op;
    b->param = temp_param;
}
void sort_single_list(JobActNode* head) {
    int swapped;
    JobActNode* ptr1;
    JobActNode* lptr = NULL;

    if (head == NULL) return;

    do {
        swapped = 0;
        ptr1 = head;

        while (ptr1->next != lptr) {
            if (ptr1->time > ptr1->next->time) {
                swap(ptr1, ptr1->next);
                swapped = 1;
            }
            ptr1 = ptr1->next;
        }
        lptr = ptr1;
    } while (swapped);
}
void update_time_difference(JobActNode* head) {
    JobActNode* current = head;
    int tmp0,tmp1;
    if(current!=NULL) tmp0=current->time;
    while (current != NULL && current->next != NULL) {
        tmp1=current->next->time;
        current->next->time = current->next->time - tmp0;     
        tmp0=tmp1;
        current = current->next;
    }
}
void sort_and_update_job_acts() {
    for (int i = 0; i < MAX_JOB_N; i++) {
        if (jobActs[i] != NULL) {
            sort_single_list(jobActs[i]);
            update_time_difference(jobActs[i]);
        }
    }
}
static void sortArriveQueue(){
    int i=0;
    
    scanf("%s %d",Ins[i].command, &Ins[i].pid);
    while(Ins[i].pid!=-1){

        vac[Ins[i].pid]=1;

        while(scanf("%d %s %d",&Ins[i].time,Ins[i].command,&Ins[i].j)==3){
            if(Ins[i].time==-1) break;
            if(strcmp(Ins[i].command,ins[0])==0){
                arrive_q[arrive_n].pid=Ins[i].pid;               
                arrive_q[arrive_n++].time=Ins[i].time;
                continue;
            }
        

            //printf("%s strcmp with %s is %d\n",Ins[i].command,ins[6], strcmp(Ins[i].command,ins[6]) );
            
            for(int j=1; j<INSNUM; j++){
                if(strcmp(Ins[i].command,ins[j])==0){
                    int k=Ins[i].pid;
                    JobActNode *J=jobActs[k];
                    jobActs[k]=malloc(sizeof(JobActNode));
                    jobActs[k]->next=J;

                    //printf("time %d op %s goto pid %d\n",Ins[i].time, Ins[i].command, Ins[i].pid);

                    
                    jobActs[k]->op=j;
                    jobActs[k]->time=Ins[i].time;
                    jobActs[k]->param=Ins[i].j;
                    if(j==POP_APPL){
                        jobs[k].resource_requests[Ins[i].j]++;
                        jobs[k].resource_remain[Ins[i].j]++;
                    }
                    break;
                }
            }
        }
        Ins[i].pid=Ins[i].j; 
    }

    
    qsort(arrive_q, arrive_n, sizeof(_Arrive), compare);
    // 计算相邻元素的 time 差值并存储到后一个元素的 time 里
    for (int i = arrive_n-1; i>0 ; i--) {
        arrive_q[i].time = arrive_q[i].time - arrive_q[i - 1].time;
    }
    sort_and_update_job_acts();
}




//试图从New队列取出一个作业送入内存成为一个进程
static void admitJobs(int T){
    //int cnt=0;
    while(!q_full(&Ready) && procN <= MAX_PROCESS_N && !q_empty(&New)) {
        //printf("[time] %d\n",cnt++);
        int pid = q_front(&New);
        jobs[pid].state = READY;
        Log(pid,"is admitted to the ready queue.",T,1);
        q_push(&Ready,pid,PSA);
        q_pop(&New);
        procN++;
        createProcess(pid, T, jobs[pid].priority,-1);
    }
}
    



void debug(){
    for(int i=0;i<2;i++){
        JobActNode * J=jobActs[i];
        while(J){
            printf("[%d] op %s conducted by process %d\n",J->time,ins[J->op],i);
            J=J->next;
        }
    }
    for(int i=0;i<arrive_n;i++){
        printf("%d pid process has arrived at time %d\n",arrive_q[i].pid, arrive_q[i].time);
    }
}

void simulator(){
    init_processes();
    sortArriveQueue();

    debug();
    //return ;

    int arrive_head=0, T=0;

    while (arrive_head<arrive_n || procN>0){
        int tslot=RR_STIME;

        //执行arrive指令
        if(arrive_head<arrive_n){
            for(int i=tslot;arrive_head<arrive_n;i-=arrive_q[arrive_head].time){
                if(i<arrive_q[arrive_head].time){
                    arrive_q[arrive_head].time-=i;
                    break;
                }
                int pid = arrive_q[arrive_head].pid;
                Log(pid,"arrives.",T+RR_STIME-i,0);
                //jobs相关数据由createProcess执行

                if(!q_full(&New)) q_push(&New, pid, FCFS);
                else {
                    LogErr("Fatal error: New Queue is full! ",T+RR_STIME-i);
                }
                arrive_head++;
            }
        }
        
        admitJobs(T);//create process from New_queue. FCFS

        //调度进程使其Running
        for (int c=0;c<CORE_N;++c){
            if(!q_empty(&Ready)){

                Running[c]=q_pop(&Ready);
                int pid=Running[c];
                if (jobs[pid].start_time==-1) //首次运行，设置start_time，即响应时间
                    jobs[pid].start_time = T;
                jobs[pid].state = RUNNING;
                Log(pid,"starts to run in CPU",T,1);
            } else {
                Running[c]=-1;
                break;
            }
            
        }   
        

        //枚举执行每个核上的进程动作
        for (int c=0;c<CORE_N;++c){
            int pid = Running[c];
            if (pid==-1) continue;
            if (_processAct(pid, T)){   //返回值表示该进程是否需要加入ready队列，1：加入；0：终止或挂起
                Log(pid,"timeSlot over and is sent back the ready queue.",T+RR_STIME,1);
                if(!q_full(&Ready))
                    q_push(&Ready,pid,PSA);
                else 
                    LogErr("Ready queue is full", T+RR_STIME);
                jobs[pid].state = READY;
            }
        }  
        T+=RR_STIME;          
            
    }

    
    free_processes();
}
